//
//
#ifndef Segment2D_h__
#define Segment2D_h__

#include "Point2D.h"
#include "Vector2D.h"

namespace Geometric
{
	class _GEOMETRIC Segment2D
	{
	public:
		// start point
		Point2D m_start;
		// end point
		Point2D m_end;

	public:
		Segment2D(const Point2D& _start, const Point2D& _end)
			: m_start(_start), m_end(_end)
		{
		}

		Segment2D(const Segment2D& _segment2D)
			: m_start(_segment2D.m_start), m_end(_segment2D.m_end)
		{
		}

		Segment2D(double _start_x, double _start_y, double _end_x, double _end_y)
			: m_start(_start_x, _start_y), m_end(_end_x, _end_y)
		{
		}

		~Segment2D()
		{
		}


	public:
		inline Segment2D& operator = (const Segment2D& _segment)
		{
			this->m_start = _segment.m_start;
			this->m_end = _segment.m_end;
			return (*this);
		}

	public:
		inline double getCross(double _dir_x, double _dir_y)
		{
			double dir_x = m_end.m_x - m_start.m_x;
			double dir_y = m_end.m_y - m_start.m_y;
			return (dir_x * _dir_y - dir_y * _dir_x);
		}

		inline double getLength()
		{
			double dx = m_end.m_x - m_start.m_x;
			double dy = m_end.m_y - m_start.m_y;
			return Gmath::toSqrt(dx * dx + dy * dy);
		}

		inline double getSquare()
		{
			double dx = m_end.m_x - m_start.m_x;
			double dy = m_end.m_y - m_start.m_y;
			return (dx * dx + dy * dy);
		}

		inline bool isInRect(double _x, double _y)
		{
			double max_x = Gmath::toMax(m_start.m_x, m_end.m_x);
			double min_x = Gmath::toMin(m_start.m_x, m_end.m_x);
			double max_y = Gmath::toMax(m_start.m_y, m_end.m_y);
			double min_y = Gmath::toMin(m_start.m_y, m_end.m_y);

			//return ((_x <= max_x) && (_x >= min_x) && (_y <= max_y) && (_y >= min_y));
			return ((Gmath::isLessAndEqual(_x, max_x) && Gmath::isLessAndEqual(min_x, _x)) && 
				(Gmath::isLessAndEqual(_y, max_y) && Gmath::isLessAndEqual(min_y, _y)));
		}

		inline bool isInRect(const Point2D& _point)
		{
			return isInRect(_point.m_x, _point.m_y);
		}

		inline bool isOnLinear(double _x, double _y)
		{
			double tmp_1 = (m_start.m_x - _x) * (m_end.m_y - _y);
			double tmp_2 = (m_start.m_y - _y) * (m_end.m_x - _x);
			return Gmath::isEqual(tmp_1, tmp_2);
		}

		inline bool isOnLinear(const Point2D& _point)
		{
			return isOnLinear(_point.m_x, _point.m_y);
		}

		inline bool isOnSegment(double _x, double _y)
		{
			return (isOnLinear(_x, _y) && isInRect(_x, _y));
		}

		inline bool isOnSegment(const Point2D& _point)
		{
			return isOnSegment(_point.m_x, _point.m_y);
		}

		inline bool isOverlap(const Segment2D& _segment)
		{
			return ((_segment.m_start == m_start && _segment.m_end == m_end) || 
				(_segment.m_end == m_start && _segment.m_start == m_end));
		}

		inline bool isIntersect(const Segment2D& _segment)
		{
			double max_x = Gmath::toMax(m_start.m_x, m_end.m_x);
			double min_x = Gmath::toMin(m_start.m_x, m_end.m_x);
			double max_y = Gmath::toMax(m_start.m_y, m_end.m_y);
			double min_y = Gmath::toMin(m_start.m_y, m_end.m_y);

			double tmp_max_x = Gmath::toMax(_segment.m_start.m_x, _segment.m_end.m_x);
			double tmp_min_x = Gmath::toMin(_segment.m_start.m_x, _segment.m_end.m_x);
			double tmp_max_y = Gmath::toMax(_segment.m_start.m_y, _segment.m_end.m_y);
			double tmp_min_y = Gmath::toMin(_segment.m_start.m_y, _segment.m_end.m_y);

			if(! (Gmath::isLess(max_x, tmp_min_x) || Gmath::isLess(tmp_max_x, min_x)
				|| Gmath::isLess(max_y, tmp_min_y) || Gmath::isLess(tmp_max_y, min_y)) )
			{
				Vector2D vec1, vec2, vec3;
				vec1.set(m_start, m_end);
				vec2.set(m_start, _segment.m_start);
				vec3.set(m_start, _segment.m_end);
				
				double tmp1 = vec1.getCross(vec2);
				double tmp2 = vec1.getCross(vec3);
				if(Gmath::isLessAndEqual(tmp1 * tmp2, 0) == true)
				{
					return true;
				}
			}

			return false;
		}
	};


}

#endif